﻿using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using VisualWip.Core;
using VisualWip.Core.Columns;
using VisualWip.Core.Interfaces;
using VisualWip.PresentationModel;
using VisualWip.PresentationModel.Group;
using VisualWip.PresentationModel.Image;
using VisualWip.PresentationModel.Line;
using VisualWip.PresentationModel.Text;
using VisualWip.PresentationModel.Uri;
using VisualWip.PresentationModel.ViewModels;
using VisualWip.PresentationModel.WorkItem;
using VisualWip.Properties;
using VisualWip.Util;

namespace VisualWip
{
    public class BootStrapper
    {
        private readonly IUnityContainer _container = new UnityContainer();
        private Application _app;
        private CompositionContainer _compositionContainer;

        public BootStrapper()
        {
            LoadContainerRegistrations();
            LoadViewModelRegistrations();
            InitProviders();
            InitApplication();
        }

        [ImportMany(typeof (IWorkItemProvider))]
        public IEnumerable<IWorkItemProvider> WorkItemProviders { get; set; }

        [ImportMany(typeof (IColumnProviderViewModel))]
        public IEnumerable<IColumnProviderViewModel> ColumnProviderViewModels { get; set; }

        [Import(typeof(IBoardRecorder),AllowDefault = true)]
        public IBoardRecorder BoardRecorder { get; set; }

        private void LoadViewModelRegistrations()
        {
            var viewModelFactory = _container.Resolve<IViewModelFactory>();
            viewModelFactory.RegisterViewModel<WorkColumnBase, WorkColumnViewModel>();


            foreach (var provider in ColumnProviderViewModels)
            {
                provider.RegisterViewModels(viewModelFactory);
            }

            viewModelFactory.RegisterViewModel<WorkInProgressGroupColumn, WorkInProgressGroupViewModel>();

            viewModelFactory.RegisterViewModel<RichTextColumn, RichTextColumnViewModel>();
            viewModelFactory.RegisterViewModel<UriColumn, UriColumnViewModel>();
            viewModelFactory.RegisterViewModel<ImageColumn, ImageColumnViewModel>();
            viewModelFactory.RegisterViewModel<GroupColumn, GroupColumnViewModel>();
            viewModelFactory.RegisterViewModel<LineColumn, LineColumnViewModel>();
            viewModelFactory.RegisterViewModel<SingleWorkItemColumn, SingleWorkItemViewModel>();

            viewModelFactory.RegisterSettingsViewModel<RichTextColumn, RichTextColumnSettingsViewModel>();
            viewModelFactory.RegisterSettingsViewModel<UriColumn, UriColumnSettingsViewModel>();
            viewModelFactory.RegisterSettingsViewModel<ImageColumn, ImageColumnSettingsViewModel>();
            viewModelFactory.RegisterSettingsViewModel<GroupColumn, GroupColumnSettingsViewModel>();
            viewModelFactory.RegisterSettingsViewModel<LineColumn, LineColumnSettingsViewModel>();
            viewModelFactory.RegisterSettingsViewModel<SingleWorkItemColumn, SingleWorkItemSettingsViewModel>();

            viewModelFactory.RegisterViewModel<SettingsPath, RecentSettingsViewModel>();
        }

        private void InitApplication()
        {
            _container.Resolve<IWindowManager>();
            _app = _container.Resolve<Application>();
            _app.Init();
        }

        private void InitProviders()
        {
            foreach (IWorkItemProvider workItemProvider in WorkItemProviders)
            {
                _container.Resolve<IColumnProviderViewModel>(workItemProvider.Name).Init();
            }
        }

        private void LoadContainerRegistrations()
        {
            var map = new ExeConfigurationFileMap {ExeConfigFilename = "unity.config"};
            Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
            var section = (UnityConfigurationSection) config.GetSection("unity");

            section.Configure(_container);


            _container.RegisterType<IViewModelFactory, ViewModelFactory>(new ContainerControlledLifetimeManager());
            _container.RegisterType<IWorkItemProviderFactory, WorkItemProviderFactory>();
            _container.RegisterType<Application>(new ContainerControlledLifetimeManager());
            _container.RegisterType<IWindowManager, WindowManager>(new ContainerControlledLifetimeManager());
            _container.RegisterType<IColumnBuilder, ColumnBuilder>();
            _container.RegisterType<ISettingsWindow, ColumnSettingsWindow>();
            _container.RegisterType<IWorkItemSizeProvider, StaticWorkItemSizeProvider>();
            _container.RegisterType<IColumnTypeProvider, StaticColumnTypeProvider>();
            _container.RegisterType<IPersistanceProvider, FilePersistanceProvider>();
            _container.RegisterType<IPathSelector, WpfDialogPathSelector>();
            _container.RegisterType<IZoomManager, ZoomManager>();

            if (Settings.Default.RecentSettingPaths != null)
            {
                _container.RegisterInstance<IList<SettingsPath>>(
                    (from string path in Settings.Default.RecentSettingPaths
                     select new SettingsPath {Path = path}).Distinct().ToList());
            }
            else
            {
                _container.RegisterInstance<IList<SettingsPath>>(new List<SettingsPath>());
            }

            ComposeProviders();
        }

        private void ComposeProviders()
        {
            string binFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var dc = new DirectoryCatalog(binFolder);

            _compositionContainer = new CompositionContainer(dc);
            var batch = new CompositionBatch();
            batch.AddPart(this);
            var columnBuilder = _container.Resolve<IColumnBuilder>();
            batch.AddExportedValue(columnBuilder);
            _compositionContainer.Compose(batch);

            foreach (IWorkItemProvider workItemProvider in WorkItemProviders)
            {
                _container.RegisterInstance(workItemProvider.Name, workItemProvider);
            }

            foreach (IColumnProviderViewModel providerViewModel in ColumnProviderViewModels)
            {
                providerViewModel.Init();
                _container.RegisterInstance(providerViewModel.ProviderName, providerViewModel);
            }

            _container.RegisterInstance(BoardRecorder ?? new DoNothingRecorder());
            _container.RegisterInstance(ColumnProviderViewModels);
        }

        public void SaveSettings()
        {
            Settings.Default.RecentSettingPaths = new StringCollection();
            foreach (SettingsPath recentSettingsPath in _app.RecentSettingsPaths)
            {
                Settings.Default.RecentSettingPaths.Add(recentSettingsPath.Path);
            }
            Settings.Default.Save();
        }
    }
}